use std::io::Read;

macro_rules! is_leap_year {
    ($year:expr) => { $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0) };
}

pub fn check_id_card(id_card_no: &str) -> String {
    let len = id_card_no.len();
    if (len != 18 && len != 15) 
         || (len == 15 && id_card_no.parse::<i64>().is_err())
         || (len == 18 && (id_card_no[..17].parse::<i64>().is_err()
             || ! matches!(id_card_no.chars().last().unwrap(), '0'..='9' | 'X')
             )
         ) {
        return String::from("身份证号码错误");
    }

    let numbers: Vec<i32> = id_card_no.chars().map(|c| {
        if c == 'X' { 10 } else { c as i32 - 48 }
    }).collect();
    if len == 18 {
        let w: [i32; 18] = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2,1];
        if numbers.iter().enumerate().map(|(i,&x)| x*w[i]).sum::<i32>() % 11 != 1 {
            return String::from("身份证号码错误");
        }
    }

    let data = get_data();
    let mut addr: String;
    let region_number = id_card_no[..6].parse::<usize>().ok().unwrap();
    if let Some(last) = data.get(region_number) {
        addr = last.clone().unwrap().to_string();
        // print!("{addr}\t");
        if region_number % 100 != 0 {
            addr = data.get(region_number / 100 * 100).unwrap().clone().unwrap() + "-" + &addr.clone();
        }
        if region_number % 10000 != 0 {
            addr = data.get(region_number / 10000 * 10000).unwrap().clone().unwrap() + "-" + &addr.clone();
        }
        // println!("{addr}");
    } else {
        return String::from("身份证号码错误");
    }

    let pos = if len == 18 {10} else {8};
    let year = if len == 18 {
        id_card_no[pos-4..pos].parse::<i32>().unwrap()
    } else {
        1900 + numbers[pos-2]*10 + numbers[pos-1]
    };
    let month = numbers[pos]*10 + numbers[pos+1];
    let day = numbers[pos+2]*10 + numbers[pos+3];
    let month_day = [0, 31, if is_leap_year!(year) {29} else {28}, 
                    31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    if !(matches!(month, 1..=12) && day > 0 && day <= month_day[month as usize]) {
        return String::from("身份证号码错误");
    }
    format!("身份证号码正确,{},{}年{:02}月{:02}日,{}", 
        if numbers[if len == 18 {16} else {14}] % 2 == 0 { "女" } else { "男" },
        year, month, day, addr
    )
}

fn get_data() -> Vec<Option<String>> {
    let mut file = match std::fs::File::open("data.txt") {
        Err(e) => panic!("无法打开文件: {}", e),
        Ok(f) => f,
    };
    let mut raw_contents = String::new();
    match file.read_to_string(&mut raw_contents) {
        Err(e) => panic!("读取文件出错: {}", e),
        Ok(_) => (),
    }
    let mut data: Vec<Option<String>> = vec![None; 1000000];
    let list: Vec<&str> = raw_contents.split("\n").filter(|&s| !s.is_empty()).collect();
    list.iter().for_each(|&s| {
        *(data.get_mut(s[..6].parse::<usize>().unwrap()).unwrap()) = Some(s[7..].to_string());
    });

    data
}
